/*
 CCCC - C and C++ Code Counter
 Copyright (C) 1994-2005 Tim Littlefair (tim_littlefair@hotmail.com)

 This program is free software; you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program; if not, write to the Free Software
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
 */
// cccc_htm.cc

// this file defines HTML output facilities for the CCCC project

#include "cccc.h"
#include "cccc_itm.h"
#include "cccc_htm.h"

// I would love to use the C++ standard preprocessor
// directive #if here, but I have had reports before now
// of people who are using compilers which only support
// #ifdef.
#ifdef CCCC_CONF_W32VC
#include <direct.h>
#else
#ifdef CCCC_CONF_W32BC
#include <direct.h>
#else
#include <unistd.h>
#endif
#endif

#include <time.h>
#include <sys/stat.h>
#include "cccc_utl.h"

typedef std::map<string, Source_Anchor> source_anchor_map_t;
source_anchor_map_t source_anchor_map;

// class static data members
CCCC_Project* CCCC_Html_Stream::prjptr;
string CCCC_Html_Stream::outdir;
string CCCC_Html_Stream::libdir;
//CCCC_Html_Stream::CCCC_Html_Stream * source_fstr;

static CCCC_Html_Stream * source_fstr;

int CCCC_Html_Stream::count;
int CCCC_Html_Stream::source_num;

void CCCC_Html_Stream::GenerateReports(CCCC_Project* prj, int report_mask,
		const string& file, const string& dir) {
	prjptr = prj;
	outdir = dir;

	CCCC_Html_Stream main_html_stream(file.c_str(),
			"Report on software metrics");

	if (report_mask & rtCONTENTS) {
		// For testing purposes, we want to be able to disable the inclusion
		// of the current time in the report.  This enables us to store a
		// reference version of the report in RCS and expect the program
		// to generate an identical one at regression testing time.
		if (report_mask & rtSHOW_GEN_TIME) {
			main_html_stream.Table_Of_Contents(report_mask, true);
		} else {
			main_html_stream.Table_Of_Contents(report_mask, false);
		}
	}

	if (report_mask & rtSUMMARY) {
		main_html_stream.Project_Summary();
	}

	if (report_mask & rtPROC1) {
		main_html_stream.Procedural_Summary();
	}

	if (report_mask & rtPROC2) {
		main_html_stream.Procedural_Detail();
	}

	if (report_mask & rtOODESIGN) {
		main_html_stream.OO_Design();
	}

	if (report_mask & rtSTRUCT1) {
		main_html_stream.Structural_Summary();
	}

	if (report_mask & rtSTRUCT2) {
		main_html_stream.Structural_Detail();
	}

	if (report_mask & rtSEPARATE_MODULES) {
		main_html_stream.Separate_Modules();
	}

	if (report_mask & rtOTHER) {
		main_html_stream.Other_Extents();
	}

	if (report_mask & rtSOURCE) {
		main_html_stream.Source_Listing();
	}

	if (report_mask & rtCCCC) {
		main_html_stream.Put_Section_Heading("About CCCC", "infocccc", 1);
		main_html_stream.fstr
				<< "<P>This report was generated by the program CCCC, which is FREELY "
				<< "REDISTRIBUTABLE but carries NO WARRANTY." << endl
				<< "<P>CCCC was developed by Tim Littlefair. " << endl
				<< "as part of a PhD research project. "
				<< "This project is now completed and descriptions of the "
				<< "findings can be accessed at "
				<< "<A HREF=http://www.chs.ecu.edu.au/~tlittlef>"
				<< "http://www.chs.ecu.edu.au/~tlittlef</A>. "
				<< "<P>User support for CCCC can be obtained by "
				<< "<A HREF=mailto:cccc-users@lists.sourceforge.net>"
				<< "mailing the list cccc-users@lists.sourceforge.net</A>."
				<< "<P>Please also visit the CCCC development website at "
				<< "<A HREF=http://cccc.sourceforge.net>http://cccc.sourceforge.net</A>."
				<< endl;
	}
}

CCCC_Html_Stream::~CCCC_Html_Stream() {
	fstr << "</BODY></HTML>" << endl;
	fstr.close();
}

void CCCC_Html_Stream::Table_Of_Contents(int report_mask, bool showGenTime) {
	// record the number of report parts in the table, and the
	// stream put pointer
	// if we find that we have only generated a single part, we supress
	// the TOC by seeking to the saved stream offset
	int number_of_report_parts = 0;
	int saved_stream_offset = fstr.tellp();

	fstr << "<TABLE BORDER WIDTH=100%>" << endl << "<TR><TH COLSPAN=2>" << endl
			<< "CCCC Software Metrics Report";
	if (prjptr->name(nlSIMPLE) != "") {
		fstr << " on project " << prjptr->name(nlSIMPLE);
	}
	fstr << endl;

	// we have the option to disable the display of the generation time
	// so that we can generate identical reports for regression testing
	if (showGenTime == true) {
		time_t generationTime = time(NULL);
		fstr << "<BR> generated " << ctime(&generationTime) << endl;
	}

	fstr << "</TR>" << endl;

	if (report_mask & rtSUMMARY) {
		Put_Section_TOC_Entry("Project Summary", "projsum",
				"Summary table of high level measures summed "
					"over all files processed in the current run.");
		number_of_report_parts++;
	}

	if (report_mask & rtPROC1) {
		Put_Section_TOC_Entry("Procedural Metrics Summary", "procsum",
				"Table of procedural measures (i.e. lines of "
					"code, lines of comment, McCabe's cyclomatic "
					"complexity summed over each module.");
		number_of_report_parts++;
	}

	if (report_mask & rtPROC2) {
		Put_Section_TOC_Entry("Procedural Metrics Detail", "procdet",
				"The same procedural metrics as in the procedural "
					"metrics summary, reported for individual "
					"functions, grouped by module.");
		number_of_report_parts++;
	}

	if (report_mask & rtOODESIGN) {
		Put_Section_TOC_Entry("Object Oriented Design", "oodesign",
				"Table of four of the 6 metrics proposed by "
					"Chidamber and Kemerer in their various papers on "
					"'a metrics suite for object oriented design'.");
		number_of_report_parts++;
	}

	if (report_mask & rtSTRUCT1) {
		Put_Section_TOC_Entry("Structural Metrics Summary", "structsum",
				"Structural metrics based on the relationships of "
					"each module with others.  Includes fan-out (i.e. "
					"number of other modules the current module "
					"uses), fan-in (number of other modules which use "
					"the current module), and the Information Flow "
					"measure suggested by Henry and Kafura, which "
					"combines these to give a measure of coupling for "
					"the module.");
		number_of_report_parts++;
	}

	if (report_mask & rtSTRUCT2) {
		Put_Section_TOC_Entry("Structural Metrics Detail", "structdet",
				"The names of the modules included as clients and "
					"suppliers in the counts for the Structural "
					"Metrics Summary.");
		number_of_report_parts++;
	}

	if (report_mask & rtOTHER) {
		Put_Section_TOC_Entry("Other Extents", "other",
				"Lexical counts for parts of submitted source "
					"files which the analyser was unable to assign to "
					"a module. Each record in this table relates to "
					"either a part of the code which triggered a "
					"parse failure, or to the residual lexical counts "
					"relating to parts of a file not associated with "
					"a specific module.");
		number_of_report_parts++;
	}

	if (report_mask & rtCCCC) {
		Put_Section_TOC_Entry("About CCCC", "infocccc",
				"A description of the CCCC program.");
		number_of_report_parts++;
	}

	fstr << "</TR></TABLE>" << endl;
	if (number_of_report_parts < 2) {
		fstr.seekp(saved_stream_offset);
	}
}

void CCCC_Html_Stream::Put_Section_Heading(string heading_title,
		string heading_tag, int heading_level) {
	fstr << "<H" << heading_level << ">" << "<A NAME=\"" << heading_tag
			<< "\">" << heading_title << "</A></H" << heading_level << ">"
			<< endl;
}

void CCCC_Html_Stream::Project_Summary() {
	Put_Section_Heading("Project Summary", "projsum", 1);

	fstr << "This table shows measures over the project as a whole." << endl;

	fstr << "<UL>" << endl;
	Metric_Description("NOM", "Number of modules",
			"Number of non-trivial modules identified by the "
				"analyser.  Non-trivial modules include all classes, "
				"and any other module for which member functions are "
				"identified.");
	Metric_Description("LOC", "Lines of Code",
			"Number of non-blank, non-comment lines of source code "
				"counted by the analyser.");
	Metric_Description("COM", "Lines of Comments",
			"Number of lines of comment identified by the analyser");
	Metric_Description("MVG", "McCabe's Cyclomatic Complexity",
			"A measure of the decision complexity of the functions "
				"which make up the program."
				"The strict definition of this measure is that it is "
				"the number of linearly independent routes through "
				"a directed acyclic graph which maps the flow of control "
				"of a subprogram.  The analyser counts this by recording "
				"the number of distinct decision outcomes contained "
				"within each function, which yields a good approximation "
				"to the formally defined version of the measure.");
	Metric_Description("L_C", "Lines of code per line of comment",
			"Indicates density of comments with respect to textual "
				"size of program");
	Metric_Description("M_C", "Cyclomatic Complexity per line of comment",
			"Indicates density of comments with respect to logical "
				"complexity of program");
	Metric_Description("IF4", "Information Flow measure",
			"Measure of information flow between modules suggested "
				"by Henry and Kafura. The analyser makes an approximate "
				"count of this by counting inter-module couplings "
				"identified in the module interfaces.");

	fstr << "</UL>" << endl
			<< "Two variants on the information flow measure IF4 are also "
			<< "presented, one (IF4v) calculated using only relationships in the "
			<< "visible part of the module interface, and the other (IF4c) "
			<< "calculated using only those relationships which imply that changes "
			<< "to the client must be recompiled of the supplier's definition "
			<< "changes." << endl << endl;

	// calculate the counts on which all displayed data will be based
	int nom = prjptr->get_count("NOM"); // number of modules
	int loc = prjptr->get_count("LOC"); // lines of code
	int mvg = prjptr->get_count("MVG"); // McCabes cyclomatic complexity
	int com = prjptr->get_count("COM"); // lines of comment
	int if4 = prjptr->get_count("IF4"); // intermodule complexity (all couplings)
	int if4v = prjptr->get_count("IF4v"); // intermodule complexity (visible only)
	int if4c = prjptr->get_count("IF4c"); // intermodule complexity (concrete only)
	int rej = prjptr->rejected_extent_table.get_count("LOC");

	fstr << "<TABLE BORDER WIDTH=100%>" << endl << "<TR>" << endl;
	Put_Header_Cell("Metric", 70);
	Put_Header_Cell("Tag", 10);
	Put_Header_Cell("Overall", 10);
	Put_Header_Cell("Per Module", 10);
	fstr << "</TR>" << endl;

	fstr << "<TR>" << endl;
	Put_Label_Cell("Number of modules");
	Put_Label_Cell("NOM");
	Put_Metric_Cell(nom);
	Put_Label_Cell("");
	fstr << "</TR>" << endl;

	fstr << "<TR>" << endl;
	Put_Label_Cell("Lines of Code", 700);
	Put_Label_Cell("LOC", 120);
	Put_Metric_Cell(loc, "LOCp");
	Put_Metric_Cell(loc, nom, "LOCper");
	fstr << "</TR>" << endl;

	fstr << "<TR>" << endl;
	Put_Label_Cell("McCabe's Cyclomatic Number");
	Put_Label_Cell("MVG");
	Put_Metric_Cell(mvg, "MVGp");
	Put_Metric_Cell(mvg, nom, "MVGper");
	fstr << "</TR>" << endl;

	fstr << "<TR>" << endl;
	Put_Label_Cell("Lines of Comment");
	Put_Label_Cell("COM");
	Put_Metric_Cell(com, "COM");
	Put_Metric_Cell(com, nom, "COMper");
	fstr << "</TR>" << endl;

	fstr << "<TR>" << endl;
	Put_Label_Cell("LOC/COM");
	Put_Label_Cell("L_C");
	Put_Metric_Cell(loc, com, "L_C");
	Put_Label_Cell("");
	fstr << "</TR>" << endl;

	fstr << "<TR>" << endl;
	Put_Label_Cell("MVG/COM");
	Put_Label_Cell("M_C");
	Put_Metric_Cell(mvg, com, "M_C");
	Put_Label_Cell("");
	fstr << "</TR>" << endl;

	fstr << "<TR>" << endl;
	Put_Label_Cell("Information Flow measure (inclusive)");
	Put_Label_Cell("IF4");
	Put_Metric_Cell(if4);
	Put_Metric_Cell(if4, nom, "8.3");
	fstr << "</TR>" << endl;

	fstr << "<TR>" << endl;
	Put_Label_Cell("Information Flow measure (visible)");
	Put_Label_Cell("IF4v");
	Put_Metric_Cell(if4v);
	Put_Metric_Cell(if4v, nom, "8.3");
	fstr << "</TR>" << endl;

	fstr << "<TR>" << endl;
	Put_Label_Cell("Information Flow measure (concrete)");
	Put_Label_Cell("IF4c");
	Put_Metric_Cell(if4c);
	Put_Metric_Cell(if4c, nom, "8.3");
	fstr << "</TR>" << endl;

	fstr << "<TR>" << endl;
	Put_Label_Cell("Lines of Code rejected by parser");
	Put_Label_Cell("REJ");
	Put_Metric_Cell(rej, "REJ");
	Put_Label_Cell("");
	fstr << "</TR>" << endl;

	fstr << "</TABLE>" << endl;
}

void CCCC_Html_Stream::OO_Design() {
	Put_Section_Heading("Object Oriented Design", "oodesign", 1);

	fstr << "<UL>" << endl;
	Metric_Description("WMC", "Weighted methods per class",
			"The sum of a weighting function over the functions of "
				"the module.  Two different weighting functions are "
				"applied: WMC1 uses the nominal weight of 1 for each "
				"function, and hence measures the number of functions, "
				"WMCv uses a weighting function which is 1 for functions "
				"accessible to other modules, 0 for private functions.");
	Metric_Description("DIT", "Depth of inheritance tree",
			"The length of the longest path of inheritance ending at "
				"the current module.  The deeper the inheritance tree "
				"for a module, the harder it may be to predict its "
				"behaviour.  On the other hand, increasing depth gives "
				"the potential of greater reuse by the current module "
				"of behaviour defined for ancestor classes.");
	Metric_Description("NOC", "Number of children",
			"The number of modules which inherit directly from the "
				"current module.  Moderate values of this measure "
				"indicate scope for reuse, however high values may "
				"indicate an inappropriate abstraction in the design.");
	Metric_Description("CBO", "Coupling between objects",
			"The number of other modules which are coupled to the "
				"current module either as a client or a supplier. "
				"Excessive coupling indicates weakness of module "
				"encapsulation and may inhibit reuse.");
	fstr << "</UL>" << endl << endl;

	fstr << "The label cell for each row in this table provides a link to "
			<< "the module summary table in the detailed report for the "
			<< "module in question" << endl;

	fstr << "<TABLE BORDER WIDTH=100%>" << endl << "<TR>" << endl;
	Put_Header_Cell("Module Name", 50);
	Put_Header_Cell("WMC1", 10);
	Put_Header_Cell("WMCv", 10);
	Put_Header_Cell("DIT", 10);
	Put_Header_Cell("NOC", 10);
	Put_Header_Cell("CBO", 10);

	fstr << "</TR>" << endl;

	CCCC_Module* mod_ptr = prjptr->module_table.first_item();
	int i = 0;
	while (mod_ptr != NULL) {
		i++;
		if (mod_ptr->is_trivial() == FALSE) {
			char *metric_tags[5] = { "WMC1", "WMCv", "DIT", "NOC", "CBO" };
			fstr << "<TR>" << endl;

			string href = mod_ptr->key() + ".html#summary";

			Put_Label_Cell(mod_ptr->name(nlSIMPLE).c_str(), 0, "", href.c_str());

			int j;
			for (j = 0; j < 5; j++) {
				CCCC_Metric metric_value(mod_ptr->get_count(metric_tags[j]),
						metric_tags[j]);
				Put_Metric_Cell(metric_value);
			}
			fstr << "</TR>" << endl;

		}
		mod_ptr = prjptr->module_table.next_item();
	}

	fstr << "</TABLE>" << endl;

}

void CCCC_Html_Stream::Procedural_Summary() {
	Put_Section_Heading("Procedural Metrics Summary", "procsum", 1);

	fstr << "For descriptions of each of these metrics see the information "
			<< "preceding the project summary table." << endl << endl;

	fstr << "The label cell for each row in this table provides a link to "
			<< "the functions table in the detailed report for the "
			<< "module in question" << endl;

	fstr << "<TABLE BORDER WIDTH=100%>" << endl << "<TR>" << endl;
	Put_Header_Cell("Module Name");
	Put_Header_Cell("LOC", 8);
	Put_Header_Cell("MVG", 8);
	Put_Header_Cell("COM", 8);
	Put_Header_Cell("L_C", 8);
	Put_Header_Cell("M_C", 8);

	fstr << "</TR>" << endl;

	CCCC_Module* mod_ptr = prjptr->module_table.first_item();
	int i = 0;
	while (mod_ptr != NULL) {
		i++;
		if (mod_ptr->is_trivial() == FALSE) {
			fstr << "<TR>" << endl;
			string href = mod_ptr->key() + ".html#procdet";

			Put_Label_Cell(mod_ptr->name(nlSIMPLE).c_str(), 0, "", href.c_str());
			int loc = mod_ptr->get_count("LOC");
			int mvg = mod_ptr->get_count("MVG");
			int com = mod_ptr->get_count("COM");
			CCCC_Metric mloc(loc, "LOCm");
			CCCC_Metric mmvg(mvg, "MVGm");
			CCCC_Metric ml_c(loc, com, "L_C");
			CCCC_Metric mm_c(mvg, com, "M_C");

			Put_Metric_Cell(mloc);
			Put_Metric_Cell(mmvg);
			Put_Metric_Cell(com);
			Put_Metric_Cell(ml_c);
			Put_Metric_Cell(mm_c);

			fstr << "</TR>" << endl;

		}
		mod_ptr = prjptr->module_table.next_item();
	}

	fstr << "</TABLE>" << endl;

}

void CCCC_Html_Stream::Structural_Summary() {
	Put_Section_Heading("Structural Metrics Summary", "structsum", 1);

	fstr << "<UL>" << endl;
	Metric_Description("FI", "Fan-in",
			"The number of other modules which pass information "
				"into the current module.");
	Metric_Description("FO", "Fan-out",
			"The number of other modules into which the current "
				"module passes information");
	Metric_Description("IF4", "Information Flow measure",
			"A composite measure of structural complexity, "
				"calculated as the square of the product of the fan-in "
				"and fan-out of a single module.  Proposed by Henry and "
				"Kafura.");
	fstr << "</UL>" << endl;

	fstr << "Note that the fan-in and fan-out are calculated by examining the "
			<< "interface of each module.  As noted above, three variants of each "
			<< "each of these measures are presented: a count restricted to the "
			<< "part of the interface which is externally visible, a count which "
			<< "only includes relationships which imply the client module needs "
			<< "to be recompiled if the supplier's implementation changes, and an "
			<< "inclusive count" << endl << endl;

	fstr << "The label cell for each row in this table provides a link to "
			<< "the relationships table in the detailed report for the "
			<< "module in question" << endl << endl;

	fstr << "<TABLE BORDER WIDTH=100%>" << endl;
	fstr << "<TR>" << endl << "<TH BGCOLOR=AQUA ROWSPAN=2>Module Name</TH>"
			<< endl << "<TH BGCOLOR=AQUA COLSPAN=3>Fan-out</TH>" << endl
			<< "<TH BGCOLOR=AQUA COLSPAN=3>Fan-in</TH>" << endl
			<< "<TH BGCOLOR=AQUA COLSPAN=3>IF4</TH>" << endl << "</TR>" << endl;
	Put_Header_Cell("vis", 7);
	Put_Header_Cell("con", 7);
	Put_Header_Cell("inc", 7);
	Put_Header_Cell("vis", 7);
	Put_Header_Cell("con", 7);
	Put_Header_Cell("incl", 7);
	Put_Header_Cell("vis", 7);
	Put_Header_Cell("con", 7);
	Put_Header_Cell("inc", 7);

	fstr << "</TR>" << endl;

	CCCC_Module* module_ptr = prjptr->module_table.first_item();
	while (module_ptr != NULL) {
		if (module_ptr->is_trivial() == FALSE) {
			fstr << "<TR>" << endl;

			int fov = module_ptr->get_count("FOv");
			int foc = module_ptr->get_count("FOc");
			int fo = module_ptr->get_count("FO");

			int fiv = module_ptr->get_count("FIv");
			int fic = module_ptr->get_count("FIc");
			int fi = module_ptr->get_count("FI");

			int if4v = module_ptr->get_count("IF4v");
			int if4c = module_ptr->get_count("IF4c");
			int if4 = module_ptr->get_count("IF4");

			// the last two arguments here turn on links to enable jumping between
			// the summary and detail cells for the same module
			string href = module_ptr->key() + ".html#structdet";
			Put_Label_Cell(module_ptr->name(nlSIMPLE).c_str(), 0, "",
					href.c_str());
			Put_Metric_Cell(CCCC_Metric(fov, "FOv"));
			Put_Metric_Cell(CCCC_Metric(foc, "FOc"));
			Put_Metric_Cell(CCCC_Metric(fo, "FO"));
			Put_Metric_Cell(CCCC_Metric(fiv, "FIv"));
			Put_Metric_Cell(CCCC_Metric(fic, "FIc"));
			Put_Metric_Cell(CCCC_Metric(fi, "FI"));
			Put_Metric_Cell(CCCC_Metric(if4v, "IF4v"));
			Put_Metric_Cell(CCCC_Metric(if4c, "IF4c"));
			Put_Metric_Cell(CCCC_Metric(if4, "IF4"));

			fstr << "</TR>" << endl;
		}
		module_ptr = prjptr->module_table.next_item();
	}
	fstr << "</TABLE>" << endl;

}

void CCCC_Html_Stream::Put_Structural_Details_Cell(CCCC_Module *mod,
		CCCC_Project *prj, int mask, UserelNameLevel nl) {
	fstr << "<TD WIDTH=50%>" << endl;

#if 0
	std::cerr << "Relationships for " << mod->name(nlMODULE_NAME)
	<< " (" << mod << ")" << std::endl;
#endif

	CCCC_Module::relationship_map_t::iterator iter;
	CCCC_Module::relationship_map_t *relationship_map = NULL;
	if (mask == rmeCLIENT) {
		relationship_map = &(mod->client_map);
	} else if (mask == rmeSUPPLIER) {
		relationship_map = &(mod->supplier_map);
	}

	if (relationship_map == NULL) {
		cerr << "unexpected relationship mask " << mask << endl;
	} else {
		for (iter = relationship_map->begin(); iter != relationship_map->end(); iter++) {
			CCCC_UseRelationship *ur_ptr = (*iter).second;
			fstr << ur_ptr->name(nl) << " ";
			AugmentedBool vis = ur_ptr->is_visible();
			AugmentedBool con = ur_ptr->is_concrete();

#if 0
			std::cerr << ur_ptr->name(nlCLIENT)
			<< " uses "
			<< ur_ptr->name(nlSUPPLIER)
			<< std::endl;
#endif

			if ((vis != abFALSE) && (con != abFALSE)) {
				fstr << "[CV] ";
			} else if (vis != abFALSE) {
				fstr << "[V] ";
			} else if (con != abFALSE) {
				fstr << "[C] ";
			}
			fstr << "<BR>" << endl;
			Put_Extent_List(*ur_ptr, true);
			fstr << "<BR>" << endl;
		}
	}
	// put a non-breaking space in to avoid the unpleasantness which
	// goes with completely empty cells
	fstr << "&nbsp;" << endl;

	fstr << "</TD>" << endl;

}

void CCCC_Html_Stream::Structural_Detail() {
	Put_Section_Heading("Structural Metrics Detail", "structdet", 1);
	fstr << "<TABLE BORDER WIDTH=100%>" << endl;
	fstr << "<TR>" << endl;
	Put_Header_Cell("Module Name", 20);
	Put_Header_Cell("Clients", 40);
	Put_Header_Cell("Suppliers", 40);
	fstr << "</TR>" << endl;

	CCCC_Module* module_ptr = prjptr->module_table.first_item();
	while (module_ptr != NULL) {
		if (module_ptr->is_trivial() == FALSE) {
			fstr << "<TR>" << endl;
			Put_Label_Cell(module_ptr->name(nlSIMPLE).c_str(), 0, "structdet",
					"structsum");
			Structural_Detail(module_ptr);
			fstr << "</TR>" << endl;
		}
		module_ptr = prjptr->module_table.next_item();
	}
	fstr << "</TABLE>" << endl;

}

void CCCC_Html_Stream::Procedural_Detail() {
	Put_Section_Heading("Procedural Metrics Detail", "procdet", 1);

	fstr << "<TABLE BORDER WIDTH=100%>" << endl;

	CCCC_Module* mod_ptr = prjptr->module_table.first_item();
	while (mod_ptr != NULL) {
		if ((mod_ptr->name(nlMODULE_TYPE) != "builtin") && (mod_ptr->name(
				nlMODULE_TYPE) != "enum") && (mod_ptr->name(nlMODULE_TYPE)
				!= "union")) {
			fstr << "<TR>" << endl;
			Put_Label_Cell(mod_ptr->name(nlSIMPLE).c_str(), 50, "procdet",
					"procsum", mod_ptr);
			Put_Header_Cell("LOC", 10);
			Put_Header_Cell("MVG", 10);
			Put_Header_Cell("COM", 10);
			Put_Header_Cell("L_C", 10);
			Put_Header_Cell("M_C", 10);

			fstr << "</TR>" << endl;
			Procedural_Detail(mod_ptr);
		}
		mod_ptr = prjptr->module_table.next_item();
	}
	fstr << "</TABLE>" << endl;
}

void CCCC_Html_Stream::Other_Extents() {
	Put_Section_Heading("Other Extents", "other", 1);
	fstr << "<TABLE BORDER WIDTH=100%>" << endl;
	fstr << "<TR>" << endl;
	Put_Header_Cell("Location", 25);
	Put_Header_Cell("Text", 45);
	Put_Header_Cell("LOC", 10);
	Put_Header_Cell("COM", 10);
	Put_Header_Cell("MVG", 10);
	fstr << "</TR>" << endl;

	if (prjptr->rejected_extent_table.records() == 0) {
		fstr << "<TR><TD COLSPAN=5>" << "&nbsp;" << "</TD></TR>" << endl;
	} else {
		CCCC_Extent *extent_ptr = prjptr->rejected_extent_table.first_item();
		while (extent_ptr != NULL) {
			fstr << "<TR>";
			Put_Extent_Cell(*extent_ptr, 0);
			Put_Label_Cell(extent_ptr->name(nlDESCRIPTION).c_str());
			Put_Metric_Cell(extent_ptr->get_count("LOC"), "");
			Put_Metric_Cell(extent_ptr->get_count("COM"), "");
			Put_Metric_Cell(extent_ptr->get_count("MVG"), "");
			fstr << "</TR>" << endl;
			extent_ptr = prjptr->rejected_extent_table.next_item();
		}
	}
	fstr << "</TABLE>" << endl;

}

void CCCC_Html_Stream::Put_Section_TOC_Entry(string section_name,
		string section_href, string section_description) {
	fstr << "<TR>" << endl << "<TH><H4><A HREF=\"#" << section_href << "\">"
			<< section_name << "</A></H4></TH>" << endl << "<TD>" << endl
			<< section_description << endl << "</TR>" << endl;
}

void CCCC_Html_Stream::Put_Header_Cell(string label, int width) {
	fstr << "<TH BGCOLOR=\"AQUA\"";
	if (width > 0) {
		fstr << " WIDTH=" << width << "%";
	}
	fstr << ">";
	if (label.size() > 0) {
		*this << label.c_str();
	} else {
		// put a non-breaking space in to avoid the strange
		// bevelling associated with empty cells
		fstr << "&nbsp;";

	}
	fstr << "</TH>";
}

void CCCC_Html_Stream::Put_Label_Cell(string label, int width, string ref_name,
		string ref_href, CCCC_Record *rec_ptr) {
	fstr << "<TD";
	if (width > 0) {
		fstr << " WIDTH=" << width << "%";
	}
	fstr << ">";

	if (ref_name.size() > 0) {
		// we need to insert an HTML "<A NAME=...> tag for the current cell
		// this enables other locations to jump in
		fstr << "<A NAME=\"" << ref_name << "\"></A>" << endl;
	}

	if (ref_href.size() > 0) {
		// we need to insert an HTML <A HREF=...> tag for the current cell
		// this enables this cell to be a link to jump out
		fstr << "<A HREF=\"" << ref_href << "\">" << endl;
		// this anchor will need to be closed after the label has been displayed
	}

	if (label.size() > 0) {
		*this << label.c_str();
	} else {
		// put a non-breaking space in to avoid the strange
		// bevelling associated with empty cells
		fstr << "&nbsp;";
	}

	if (ref_href.size() > 0) {
		// closing the anchor we opened above
		fstr << "</A>" << endl;
	}

	if (rec_ptr != 0) {
		fstr << "<BR>" << endl;
		Put_Extent_List(*rec_ptr, true);
	}

	fstr << "</TD>";
}

void CCCC_Html_Stream::Put_Metric_Cell(int count, string tag, int width) {
	CCCC_Metric m(count, tag.c_str());
	Put_Metric_Cell(m, width);
}

void CCCC_Html_Stream::Put_Metric_Cell(int num, int denom, string tag,
		int width) {
	CCCC_Metric m(num, denom, tag.c_str());
	Put_Metric_Cell(m, width);
}

void CCCC_Html_Stream::Put_Metric_Cell(const CCCC_Metric& metric, int width) {
	fstr << "<TD ALIGN=RIGHT";

	if (width > 0) {
		fstr << " WIDTH=" << width << "%";
	}

	switch (metric.emphasis_level()) {
	case elMEDIUM:
		fstr << " BGCOLOR=\"YELLOW\"";
		break;
	case elHIGH:
		fstr << " BGCOLOR=\"RED\"";
		break;
	default:
		// no background colour
		break;
	}
	fstr << ">";

	*this << metric;
	fstr << "</TD>";
}

void CCCC_Html_Stream::Put_Extent_URL(const CCCC_Extent& extent) {
	string filename = extent.name(nlFILENAME);
	int linenumber = atoi(extent.name(nlLINENUMBER).c_str());

	Source_Anchor anchor(filename, linenumber);
	string key = anchor.key();
	source_anchor_map_t::value_type anchor_value(key, anchor);
	source_anchor_map.insert(anchor_value);

	anchor.Emit_HREF(fstr);
	fstr
	// << extent.name(nlDESCRIPTION) 
			<< "<BR>" << endl;
}

void CCCC_Html_Stream::Put_Extent_Cell(const CCCC_Extent& extent, int width,
		bool withDescription) {
	fstr << "<TD";
	if (width > 0) {
		fstr << " WIDTH=" << width << "%>";
	} else {
		fstr << ">";
	}
	if (withDescription) {
		fstr << extent.name(nlDESCRIPTION) << " &nbsp;" << endl;
	}
	Put_Extent_URL(extent);
	fstr << "</TD>" << endl;
}

void CCCC_Html_Stream::Put_Extent_List(CCCC_Record& record,
		bool withDescription) {
	CCCC_Extent *ext_ptr = record.extent_table.first_item();
	while (ext_ptr != NULL) {
		if (withDescription) {
			fstr << ext_ptr->name(nlDESCRIPTION) << " &nbsp;" << endl;
		}
		Put_Extent_URL(*ext_ptr);
		ext_ptr = record.extent_table.next_item();
	}
	fstr << "<BR>" << endl;
}

// the next two methods define the two basic output operations through which
// all of the higher level output operations are composed
CCCC_Html_Stream& operator <<(CCCC_Html_Stream& os, const string& stg) {
	// initialise a character pointer to the start of the string's buffer
	const char *cptr = stg.c_str();
	while (*cptr != '\000') {
		char c = *cptr;

		// the purpose of this is to filter out the characters which
		// must be escaped in HTML
		switch (c) {
		case '>':
			os.fstr << "&gt;";
			break;
		case '<':
			os.fstr << "&lt;";
			break;
		case '&':
			os.fstr << "&amp;";
			break;
			// commas and parentheses do not need to be escaped, but
			// we want to allow line breaking just inside
			// parameter lists and after commas
			// we insert a non-breaking space to guarantee a small indent
			// on the new line, and one before the right parenthesis for
			// symmetry
		case ',':
			os.fstr << ", &nbsp;";
			break;
		case '(':
			os.fstr << "( &nbsp;";
			break;
		case ')':
			os.fstr << "&nbsp;)";
			break;
		default:
			os.fstr << c;
		}
		cptr++;
	}
	return os;
}

CCCC_Html_Stream& operator <<(CCCC_Html_Stream& os, const CCCC_Metric& mtc) {
	char *emphasis_prefix[] = { "", "<EM>", "<STRONG>" };
	char *emphasis_suffix[] = { "", "</EM>", "</STRONG>" };

	// by writing to the underlying ostream object, we avoid the escape
	// functionality
	os.fstr << emphasis_prefix[mtc.emphasis_level()] << mtc.value_string()
			<< emphasis_suffix[mtc.emphasis_level()];
	return os;
}

void CCCC_Html_Stream::Separate_Modules() {
	// this function generates a separate HTML report for each non-trivial
	// module in the database

	CCCC_Module* mod_ptr = prjptr->module_table.first_item();
	while (mod_ptr != NULL) {
		int trivial_module = mod_ptr->is_trivial();
		if (trivial_module == FALSE) {
			string info = "Detailed report on module " + mod_ptr->key();
			string filename = outdir;
			filename += "/";
			filename += mod_ptr->key() + ".html";
			CCCC_Html_Stream module_html_str(filename, info.c_str());

			module_html_str.Put_Section_Heading(info.c_str(), "summary", 1);

			module_html_str.Module_Summary(mod_ptr);

			module_html_str.Put_Section_Heading("Definitions and Declarations",
					"modext", 2);
			module_html_str.fstr << "<TABLE BORDER WIDTH=100%><TR>" << endl;
			module_html_str.Put_Label_Cell("Description", 50);
			module_html_str.Put_Header_Cell("LOC", 10);
			module_html_str.Put_Header_Cell("MVG", 10);
			module_html_str.Put_Header_Cell("COM", 10);
			module_html_str.Put_Header_Cell("L_C", 10);
			module_html_str.Put_Header_Cell("M_C", 10);
			module_html_str.Module_Detail(mod_ptr);
			module_html_str.fstr << "</TR></TABLE>" << endl;

			module_html_str.Put_Section_Heading("Functions", "proc", 2);
			module_html_str.fstr << "<TABLE BORDER WIDTH=100%><TR>" << endl;
			module_html_str.Put_Label_Cell("Function prototype", 50);
			module_html_str.Put_Header_Cell("LOC", 10);
			module_html_str.Put_Header_Cell("MVG", 10);
			module_html_str.Put_Header_Cell("COM", 10);
			module_html_str.Put_Header_Cell("L_C", 10);
			module_html_str.Put_Header_Cell("M_C", 10);
			module_html_str.Procedural_Detail(mod_ptr);
			module_html_str.fstr << "</TR></TABLE>" << endl;

			module_html_str.Put_Section_Heading("Relationships", "structdet", 2);
			module_html_str.fstr << "<TABLE BORDER WIDTH=100%>" << endl
					<< "<TR><TH WIDTH=50%>Clients</TH><TH WIDTH=50%>Suppliers</TH></TR>"
					<< endl << "<TR>" << endl;
			module_html_str.Structural_Detail(mod_ptr);
			module_html_str.fstr << "</TR></TABLE>" << endl;

		} else {
#if 0
			cerr << mod_ptr->module_type << " " << mod_ptr->key()
			<< " is trivial" << endl;
#endif
		}
		mod_ptr = prjptr->module_table.next_item();
	}
}

void CCCC_Html_Stream::Module_Detail(CCCC_Module *module_ptr) {
	// this function generates the contents of the table of definition
	// and declaration extents for a single module

	// the output needs to be enveloped in a pair of <TABLE></TABLE> tags
	// these have not been put within the function because it is designed
	// to be used in two contexts:
	// 1. within the Separate_Modules function, wrapped directly in the table
	//    tags
	// 2. within the Module_Detail function, where the table tags are
	//    around the output of many calls to this function (not yet implemented)

	CCCC_Record::Extent_Table::iterator eIter =
			module_ptr->extent_table.begin();
	if (eIter == module_ptr->extent_table.end()) {
		fstr << "<TR><TD COLSPAN=6>"
				<< "No module extents have been identified for this module"
				<< "</TD></TR>" << endl;
	} else {
		while (eIter != module_ptr->extent_table.end()) {
			CCCC_Extent *ext_ptr = (*eIter).second;
			fstr << "<TR>" << endl;
			Put_Extent_Cell(*ext_ptr, 0, true);
			int loc = ext_ptr->get_count("LOC");
			int mvg = ext_ptr->get_count("MVG");
			int com = ext_ptr->get_count("COM");
			CCCC_Metric mloc(loc, "LOCf");
			CCCC_Metric mmvg(mvg, "MVGf");
			CCCC_Metric ml_c(loc, com, "L_C");
			CCCC_Metric mm_c(mvg, com, "M_C");

			Put_Metric_Cell(mloc);
			Put_Metric_Cell(mmvg);
			Put_Metric_Cell(com);
			Put_Metric_Cell(ml_c);
			Put_Metric_Cell(mm_c);
			fstr << "</TR>" << endl;

			eIter++;
		}
	}

	fstr << "<TR><TD HEIGHT=12 COLSPAN=6></TD></TR>" << endl;
}

void CCCC_Html_Stream::Procedural_Detail(CCCC_Module *module_ptr) {
	// this function generates the contents of the procedural detail table
	// relating to a single module

	// the output needs to be enveloped in a pair of <TABLE></TABLE> tags
	// these have not been put within the function because it is designed
	// to be used in two contexts:
	// 1. within the Separate_Modules function, wrapped directly in the table
	//    tags
	// 2. within the Procedural_Detail function, where the table tags are
	//    around the output of many calls to this function

	CCCC_Module::member_map_t::iterator iter = module_ptr->member_map.begin();

	if (iter == module_ptr->member_map.end()) {
		fstr << "<TR><TD COLSPAN=6>"
				<< "No member functions have been identified for this module"
				<< "</TD></TR>" << endl;
	} else {
		while (iter != module_ptr->member_map.end()) {
			CCCC_Member *mem_ptr = (*iter).second;
			fstr << "<TR>" << endl;
			Put_Label_Cell(mem_ptr->name(nlLOCAL).c_str(), 0, "", "", mem_ptr);
			int loc = mem_ptr->get_count("LOC");
			int mvg = mem_ptr->get_count("MVG");
			int com = mem_ptr->get_count("COM");
			CCCC_Metric mloc(loc, "LOCf");
			CCCC_Metric mmvg(mvg, "MVGf");
			CCCC_Metric ml_c(loc, com, "L_C");
			CCCC_Metric mm_c(mvg, com, "M_C");

			Put_Metric_Cell(mloc);
			Put_Metric_Cell(mmvg);
			Put_Metric_Cell(com);
			Put_Metric_Cell(ml_c);
			Put_Metric_Cell(mm_c);
			fstr << "</TR>" << endl;

			iter++;
		}
	}
	fstr << "<TR><TD HEIGHT=12 COLSPAN=6></TD></TR>" << endl;
}

void CCCC_Html_Stream::Metric_Description(string abbreviation, string name,
		string description) {
	// this is intended to be called in the context of an unnumbered list
	fstr << "<LI>" << abbreviation << " = " << name << "<BR>" << endl
			<< description << endl;
}

void CCCC_Html_Stream::Structural_Detail(CCCC_Module *module_ptr) {
	Put_Structural_Details_Cell(module_ptr, prjptr, rmeCLIENT, nlCLIENT);
	Put_Structural_Details_Cell(module_ptr, prjptr, rmeSUPPLIER, nlSUPPLIER);
}

void CCCC_Html_Stream::Module_Summary(CCCC_Module *module_ptr) {
	// calculate the counts on which all displayed data will be based
	// int nof=module_ptr->member_table.records(); // Number of functions
	int nof = 0;
	int loc = module_ptr->get_count("LOC"); // lines of code
	int mvg = module_ptr->get_count("MVG"); // McCabes cyclomatic complexity
	int com = module_ptr->get_count("COM"); // lines of comment

	// the variants of IF4 measure information flow and couplings
	int if4 = module_ptr->get_count("IF4"); // (all couplings)
	int if4v = module_ptr->get_count("IF4v"); // (visible only)
	int if4c = module_ptr->get_count("IF4c"); // (concrete only)

	int wmc1 = module_ptr->get_count("WMC1"); // Weighted methods/class (unity)
	int wmcv = module_ptr->get_count("WMCv"); // Weighted methods/class (visible)
	int dit = module_ptr->get_count("DIT"); // depth of inheritance tree
	int noc = module_ptr->get_count("NOC"); // number of children
	int cbo = module_ptr->get_count("CBO"); // coupling between objects

	fstr << "<TABLE BORDER WIDTH=100%>" << endl << "<TR>" << endl;
	Put_Header_Cell("Metric", 70);
	Put_Header_Cell("Tag", 10);
	Put_Header_Cell("Overall", 10);
	Put_Header_Cell("Per Function", 10);
	fstr << "</TR>" << endl;

	fstr << "<TR>" << endl;
	Put_Label_Cell("Lines of Code");
	Put_Label_Cell("LOC");
	Put_Metric_Cell(loc, "LOCm");
	Put_Metric_Cell(loc, nof, "LOCg");
	fstr << "</TR>" << endl;

	fstr << "<TR>" << endl;
	Put_Label_Cell("McCabe's Cyclomatic Number");
	Put_Label_Cell("MVG");
	Put_Metric_Cell(mvg, "MVGm");
	Put_Metric_Cell(mvg, nof, "MVGf");
	fstr << "</TR>" << endl;

	fstr << "<TR>" << endl;
	Put_Label_Cell("Lines of Comment");
	Put_Label_Cell("COM");
	Put_Metric_Cell(com, "COMm");
	Put_Metric_Cell(com, nof, "8.3");
	fstr << "</TR>" << endl;

	fstr << "<TR>" << endl;
	Put_Label_Cell("LOC/COM");
	Put_Label_Cell("L_C");
	Put_Metric_Cell(loc, com, "L_C");
	Put_Label_Cell("");
	fstr << "</TR>" << endl;

	fstr << "<TR>" << endl;
	Put_Label_Cell("MVG/COM");
	Put_Label_Cell("M_C");
	Put_Metric_Cell(mvg, com, "M_C");
	Put_Label_Cell("");
	fstr << "</TR>" << endl;

	fstr << "<TR>" << endl;
	Put_Label_Cell("Weighted Methods per Class (weighting = unity)");
	Put_Label_Cell("WMC1");
	Put_Metric_Cell(wmc1);
	Put_Label_Cell(""); // wmc1 should be identical to nof
	fstr << "</TR>" << endl;

	fstr << "<TR>" << endl;
	Put_Label_Cell("Weighted Methods per Class (weighting = visible)");
	Put_Label_Cell("WMCv");
	Put_Metric_Cell(wmcv);
	Put_Label_Cell("");
	fstr << "</TR>" << endl;

	fstr << "<TR>" << endl;
	Put_Label_Cell("Depth of Inheritance Tree");
	Put_Label_Cell("DIT");
	Put_Metric_Cell(dit);
	Put_Label_Cell("");
	fstr << "</TR>" << endl;

	fstr << "<TR>" << endl;
	Put_Label_Cell("Number of Children");
	Put_Label_Cell("NOC");
	Put_Metric_Cell(noc);
	Put_Label_Cell("");
	fstr << "</TR>" << endl;

	fstr << "<TR>" << endl;
	Put_Label_Cell("Coupling between objects");
	Put_Label_Cell("CBO");
	Put_Metric_Cell(cbo);
	Put_Label_Cell("");
	fstr << "</TR>" << endl;

	fstr << "<TR>" << endl;
	Put_Label_Cell("Information Flow measure (inclusive)");
	Put_Label_Cell("IF4");
	Put_Metric_Cell(if4, 1, "IF4");
	Put_Metric_Cell(if4, nof, "8.3");
	fstr << "</TR>" << endl;

	fstr << "<TR>" << endl;
	Put_Label_Cell("Information Flow measure (visible)");
	Put_Label_Cell("IF4v");
	Put_Metric_Cell(if4v, 1, "IF4v");
	Put_Metric_Cell(if4v, nof, "8.3");
	fstr << "</TR>" << endl;

	fstr << "<TR>" << endl;
	Put_Label_Cell("Information Flow measure (concrete)");
	Put_Label_Cell("IF4c");
	Put_Metric_Cell(if4c, 1, "IF4c");
	Put_Metric_Cell(if4c, nof, "8.3");
	fstr << "</TR>" << endl;

	fstr << "</TABLE>" << endl;
}

CCCC_Html_Stream::CCCC_Html_Stream(const string& fname, const string& info) {
	// cerr << "Attempting to open file in directory " << outdir.c_str() << endl;

	//	cout << "!@#$ fame :" << fname << endl;

	source_num = 0;

	fstr.open(fname.c_str());
	if (fstr.good() != TRUE) {
		cerr << "failed to open " << fname.c_str()
				<< " for output in directory " << outdir.c_str() << endl;
		exit(1);
	} else {
		// cerr << "File: " << fname << " Info: " << info << endl;
	}

	fstr << "<HTML><HEAD><TITLE>" << endl << info << endl << "</TITLE>" << endl
			<< "</HEAD>" << endl << "<BODY>" << endl;
}

int setup_anchor_data() {
	int i = 0;
	Source_Anchor a1("cccc_use.h", 12);
	Source_Anchor a2("cccc_htm.h", 15);
	i++;
	string key1 = a1.key(), key2 = a2.key();
	i++;
	source_anchor_map_t::value_type v1(key1, a1);
	source_anchor_map_t::value_type v2(key2, a2);
	i++;
	source_anchor_map.insert(v1);
	source_anchor_map.insert(v2);
	return i;
}

void CCCC_Html_Stream::Source_Listing() {
	// The variable stream src_str used to be an instance
	// of fstream which gets reopened many times.
	// this worked under Linux but broke under Win32, so
	// this variable is now a pointer which is repeatedly
	// deleted and new'ed

	string current_filename;
	int file_num = 0;
	int current_line = 0;
	int next_anchor_required = 0;
	ifstream *src_str = NULL;
	const char *style_open = "<TT>", *style_close = "</TT>";

	string filename = outdir;
	filename += "/cccc_src.html";
	CCCC_Html_Stream source_html_str(filename.c_str(), "source file");

	source_html_str.fstr << style_open << endl;

	source_anchor_map_t::iterator iter = source_anchor_map.begin();
	while (iter != source_anchor_map.end()) {
		int point = 1;
		char linebuf[1024];
		Source_Anchor& nextAnchor = (*iter).second;
		if (current_filename != nextAnchor.get_file()) {
			file_num++;
			current_filename = nextAnchor.get_file();
			current_line = 0;
			delete src_str;
			src_str = new ifstream(current_filename.c_str(), std::ios::in);
			src_str->getline(linebuf, 1023);
			source_html_str.fstr << style_close << endl;
			source_html_str.Put_Section_Heading(current_filename.c_str(), "", 1);
			source_html_str.fstr << style_open << endl;
		}

		while (src_str->good()) {
			current_line++;

			(*iter).second.Emit_NAME(source_html_str.fstr, point++);

			source_html_str << linebuf;
			source_html_str.fstr << "<BR>" << endl;
			src_str->getline(linebuf, 1023);
		}

		//		 if	there are any remaining anchors for this file the sorting
		//	by line number must be wrong
		//	complain and ignore
		while ((iter != source_anchor_map.end()) && (current_filename
				== (*iter).second.get_file())) {
			(*iter).second.Emit_NAME(source_html_str.fstr, point++);
			iter++;
			source_html_str.fstr << "<BR>" << endl;
		}

	}

	// delete the last input stream created
	delete src_str;

	source_html_str.fstr << style_close << endl;

	source_html_str.fstr << "<h2>" << prjptr->module_table.size()
			<< " modules in module table</h2>" << endl;

	source_html_str.fstr << "<h2>" << file_num << " files are listed</h2>"
			<< endl;

	source_html_str.fstr << "<h2>" << source_anchor_map.size()
			<< " source_anchor_map are listed</h2>" << endl;

	source_html_str.fstr << " </BODY></HTML>" << endl;

}

static string pad_string(int target_width, string the_string, string padding) {
	int spaces_required = target_width - the_string.size();
	string pad_string;
	while (spaces_required > 0) {
		pad_string += padding;
		spaces_required--;
	}
	return pad_string + the_string;
}

string Source_Anchor::key() const {
	string retval;
	char linebuf[16];
	sprintf(linebuf, "%d", line_);
	retval = file_ + ":" + pad_string(10, linebuf, " ");
	return retval;
}

string Source_Anchor::key_int(int line) const {
	string retval;
	char linebuf[16];

	sprintf(linebuf, "%d", line);
	retval = file_ + ":" + pad_string(10, linebuf, " ");

	return retval;
}

void Source_Anchor::Emit_HREF(ofstream& fstr) {
	string anchor_key = key();

	fstr << "<CODE><A HREF=\"cccc_src.html#" << anchor_key.c_str() << "\">"
			<< file_.c_str() << ":" << line_ << "</A></CODE>";
}

void Source_Anchor::Emit_NAME(ofstream& fstr, int line) {
	string anchor_key = key_int(line);
	char ln_buf[32];
	sprintf(ln_buf, "%d", line);
	string ln_string = pad_string(8, ln_buf, "&nbsp;");
	string space_string = pad_string(2, "", "&nbsp;");

	fstr << "<A NAME=\"" << anchor_key.c_str() << "\">" << ln_string.c_str()
			<< space_string.c_str() << "</A>";
}

void Source_Anchor::Emit_NAME(ofstream& fstr) {
	string anchor_key = key();
	char ln_buf[32];
	sprintf(ln_buf, "%d", line_);
	string ln_string = pad_string(8, ln_buf, "&nbsp;");
	string space_string = pad_string(2, "", "&nbsp;");
	fstr << "<A NAME=\"" << anchor_key.c_str() << "\">" << ln_string.c_str()
			<< space_string.c_str() << "</A>";
}

void Source_Anchor::Emit_SPACE(ofstream& fstr) {
	string space_string = pad_string(10, "", "&nbsp;");
	fstr << space_string.c_str();
}

void Emit_NAME_MODIFY(ofstream& fstr, int line, string file, string name) {
	string anchor_key;
	char linebuf[16];

	sprintf(linebuf, "%d", line);
	anchor_key = file + ":" + pad_string(10, linebuf, " ");

	char ln_buf[32];
	sprintf(ln_buf, "%d", line);
	string ln_string = pad_string(8, ln_buf, "&nbsp;");
	string space_string = pad_string(2, "", "&nbsp;");

	fstr << "<A NAME=\"" << anchor_key.c_str() << "\">" << ln_string.c_str()
			<< space_string.c_str() << "</A>";
}

// TODO

/**********************************************************************************
 **********************************************************************************
 **********************************************************************************
 **********************************************************************************
 **********************************************************************************
 **********************************************************************************/
void CCCC_Html_Stream::source_list_modify(const string& file_name) {
	source_num++;
	const char *style_open = "<TT>", *style_close = "</TT>";
	char linebuf[1024];
	int point = 1;

#ifdef DEBUG
	cout << "# list source " << endl;
	cout << "source list m enter" << endl;
	cout << file_name << endl;
#endif

	ifstream * src_str = new ifstream(file_name.c_str(), std::ios::in);

	char linebuf_temp[16];
	sprintf(linebuf_temp, "%d", 0);

	string hint = file_name + ":" + pad_string(10, linebuf_temp, " ");

	source_fstr->fstr << style_close << endl;
	source_fstr->Put_Section_Heading(file_name.c_str(), hint, 1);
	source_fstr->fstr << style_open << endl;

	src_str->getline(linebuf, 1023);

	while (src_str->good()) {
		Emit_NAME_MODIFY(source_fstr->fstr, point++, file_name, file_name);

		source_fstr->fstr << linebuf;
		source_fstr->fstr << "<BR>" << endl;
		src_str->getline(linebuf, 1023);
	}

	delete src_str;

	source_fstr->fstr << style_close << endl;

}

CCCC_Html_Stream::CCCC_Html_Stream(NodeImp* node, const string& fname,
		const string& info, int nest) {
	// cerr << "Attempting to open file in directory " << outdir.c_str() << endl;

	if (node->get_type() != ntFile) {
		string dir = outdir + "/" + node->get_path();
#ifdef _WIN32
		_mkdir(dir.c_str());
#else
		mkdir(dir.c_str(), 0777);
#endif
	}

	fstr.open(fname.c_str());

	if (fstr.good() != TRUE) {
		cerr << "failed to open " << fname.c_str()
				<< " for output in directory " << outdir.c_str() << endl;
		exit(1);
	} else {
		// cerr << "File: " << fname << " Info: " << info << endl;
	}

	fstr << "<HTML><HEAD><TITLE>" << endl << info << endl << "</TITLE>" << endl;

	string up = "";

	for (int i = 0; i < nest - 1; i++)
		up += "../";

	if (nest > 0 && node->get_type() != ntFile)
		up += "../";

	fstr << "<link href=\"" << up
			<< "../assets/lib/plugin/tabletree/stylesheets/tree_table.css\" rel=\"stylesheet\" type=\"text/css\" />"
			<< endl;
	fstr << "<link href=\"" << up
			<< "../assets/master.css\" rel=\"stylesheet\" type=\"text/css\" />"
			<< endl;
	fstr << "<script type=\"text/javascript\" src=\"" << up
			<< "../assets/lib/jquery/jquery-1.3.2.js\"" << " >" << endl
			<< "</script>" << endl;
	fstr << "<script type=\"text/javascript\" src=\"" << up
			<< "../assets/lib/plugin/tabletree/jquery.acts_as_tree_table.js\""
			<< " >" << endl << "</script>" << endl;
	fstr << "<script type=\"text/javascript\" src=\"" << up
			<< "../assets/lib/plugin/treehover/jquery.columnhover.js\"" << " >"
			<< endl << "</script>" << endl;
	fstr << "<script type=\"text/javascript\" src=\"" << up
			<< "../assets/load.js\"" << " >" << endl << "</script>" << endl;

	fstr << "</head>" << "<body>" << endl;
}

void CCCC_Html_Stream::GenerateReports(NodeImp* node, const string& file,
		const string& dir) {
	//	prjptr = prj;
	outdir = dir;

	CCCC_Module* module_ptr = prjptr->module_table.first_item();

	string source_file = outdir + "/";

	source_file += "proj_source.html";

	string file_path = outdir + "/";
	file_path += node->get_path();

	source_fstr = new CCCC_Html_Stream(source_file.c_str(), "source file");

	if (node->get_name() != "")
		file_path += node->get_name();
	else
		file_path += "project.summary";

	file_path += ".mod.html";

	CCCC_Html_Stream html_stream(node, file_path.c_str(),
			"Report on software metrics", 0);

	html_stream.generate_process(node, 0);

	source_fstr->fstr << "<h2>" << source_num
			<< " files' sources are listed</h2>" << endl;
}

void CCCC_Html_Stream::generate_process(NodeImp* node, int nest) {
	//	if (node->get_type() == ntFile)
	//		this->source_list_modify(node->getAbs_path());

	this->produce_head_table(node, nest);
	this->produce_violation_table(node, nest);

	if (node->get_type() == ntFile) {
		this->source_list_modify(node->getAbs_path());
		this->produce_function_table(node, nest);
	}

	this->produce_metrics_table(node);

	//	cout << "### node type:" << node->get_type() << endl;

	if (node->get_type() != ntProj)
		this->produce_fan_table(node, nest);

	//	cout << "###1545" << endl;

	std::vector<NodeImp *>::iterator itr;

	for (itr = node->get_children()->begin(); itr
			!= node->get_children()->end(); itr++) {
		string file_path = outdir + "/";
		file_path += (*itr)->get_path();

		//		cout << "### 1554" << endl;

		//		cout << "file_path :" << file_path << endl;
		//
		//		cout << "node name :" << (*itr)->get_name() << endl;

		if ((*itr)->get_type() == ntFile) {
			file_path += (*itr)->get_name();
			file_path += ".file.html";
		} else {
			file_path += (*itr)->get_name();
			file_path += ".mod.html";
		}

		//		cout << "###1564" << endl;

		CCCC_Html_Stream html_stream((*itr), file_path.c_str(),
				"Report on software metrics", nest + 1);

		//		cout << "### 1565" << endl;

		html_stream.generate_process((*itr), nest + 1);
	}

}

void CCCC_Html_Stream::produce_head_table(NodeImp* node, int nest) {
	count = 0;
	fstr << "<table class=\"example\">" << endl;

	put_table_captain(node->get_type());
	put_head_table_header();

	fstr << "<tbody>" << endl;

	if (node->get_type() != ntProj)
		put_parent_link(node);

	//	cout << "## type:" << node->get_type() << endl;

	if (node->get_type() != ntFile)
		produce_tree_cell(node, -1, nest);
	else
		produce_file_dispatch(node);

	fstr << "</tbody>" << endl;
	fstr << "</table>" << endl;
}

void CCCC_Html_Stream::produce_file_dispatch(NodeImp* node) {
	fstr << "<tr id=\"node-1\" >";

	put_file_dispatch(node, 0);

	fstr << "</tr>";
	//TODO
}

void CCCC_Html_Stream::produce_tree_cell(NodeImp* node, int parent, int depth) {
	int index = count;
	fstr << "<tr id=\"node-" << count++ << "\" ";
	if (parent >= 0)
		fstr << "class=\"child-of-node-" << parent << "\"";
	fstr << ">" << endl;
	put_cell_value(node, depth);

	fstr << "</tr>" << endl;

	std::vector<NodeImp *>::iterator itr;

	for (int i = 0; i < node->get_children()->size(); i++) {
		produce_tree_cell(node->get_children()->at(i), index, depth + 1);
	}
}

void CCCC_Html_Stream::put_file_dispatch(NodeImp* node, int depth) {

	//TODO
	char linebuf[16];
	sprintf(linebuf, "%d", 0);

	string hint = node->getAbs_path() + ":" + pad_string(10, linebuf, " ");

	fstr << "<td>" << endl;
	fstr << "<span class=\"file" << "\">";

	fstr << "<a href=\"file:///" << outdir << "/proj_source.html#" << hint
			<< "\">" << node->get_name() << "</a>";

	fstr << "</span>" << endl;
	fstr << "</td>" << endl;

	put_td_int(node->get_NOC());
	put_td_int(node->get_NOM());
	put_td_int(node->get_NOSM());
	put_td_int(node->get_NOF());
	put_td_int(node->get_NOFA());
	put_td_int(node->getLineOfCode());
	put_td_int(node->get_MVG());
	put_td_int(node->get_NOV());
}

void CCCC_Html_Stream::put_cell_value(NodeImp* node, int depth) {
	string node_type = "folder";

	if (node->get_type() == ntFile)
		node_type = "file";

	string nest = "";

	for (int i = 0; i < depth - 1; i++)
		nest += "../";

	//	if (depth > 0 && node->get_type() != ntFile)
	//		nest += "../";

	fstr << "<td>" << endl;
	fstr << "<span class=\"" << node_type << "\">";
	if (node->get_type() == ntFile) {
		fstr << "<a href=\"file:///" << outdir << "/" << node->get_path()
				<< node->get_name() << ".file.html" << "\">"
				<< node->get_name() << "</a>";
	} else {
		fstr << "<a href=\"file:///" << outdir << "/" << node->get_path()
				<< node->get_name() << ".mod.html" << "\">" << node->get_name()
				<< "</a>";
	}
	fstr << "</span>" << endl;
	fstr << "</td>" << endl;

	put_td_int(node->get_NOC());
	put_td_int(node->get_NOM());
	put_td_int(node->get_NOSM());
	put_td_int(node->get_NOF());
	put_td_int(node->get_NOFA());
	put_td_int(node->getLineOfCode());
	put_td_int(node->get_MVG());
	put_td_int(node->get_NOV());
}

void CCCC_Html_Stream::put_td_int(int value) {
	char ln_buf[16];
	sprintf(ln_buf, "%d", value);

	if (value >= 0)
		fstr << "<td>" << ln_buf << "</td>" << endl;
	else
		fstr << "<td>--</td>" << endl;
}

void CCCC_Html_Stream::put_parent_link(NodeImp* node) {
	fstr << "<tr>" << endl;
	fstr << "<td>" << endl;

	if (node->get_type() == ntFile)
		fstr << "<span class=\"folder\"><a href=\""
				<< node->get_parent()->get_name() << ".mod.html"
				<< "\">..</a></span>" << endl;
	else
		fstr << "<span class=\"folder\"><a href=\"../"
				<< node->get_parent()->get_name() << ".mod.html"
				<< "\">..</a></span>" << endl;
	fstr << "</td>" << endl;
	fstr << "</tr>" << endl;
}

void CCCC_Html_Stream::put_table_captain(int type) {
	switch (type) {
	case ntProj:
		fstr << "<caption>" << "Project Summary" << "</caption>" << endl;
	case ntCom:
		fstr << "<caption>" << "Component Summary" << "</caption>" << endl;
	case ntMod:
		fstr << "<caption>" << "Module Summary" << "</caption>" << endl;
	case ntSmod:
		fstr << "<caption>" << "Sub Module Summary" << "</caption>" << endl;
	default:
		fstr << "<caption>" << "File Summary" << "</caption>" << endl;
	}
}

void CCCC_Html_Stream::put_th(string header) {
	fstr << "<th>" << header << "</th>" << endl;
}

void CCCC_Html_Stream::put_head_table_header() {
	fstr << "<thead>" << endl;
	fstr << "<tr>" << endl;

	put_th("Module Name");
	put_th("NOC");
	put_th("NOM");
	put_th("NOSM");
	put_th("NOF");
	put_th("NOFA");
	put_th("LOC");
	put_th("MVG");
	put_th("NOV");

	fstr << "</tr>" << endl;
	fstr << "</thead>" << endl;
}

void CCCC_Html_Stream::produce_metrics_table(NodeImp* node) {
	fstr << "<br><br><br>" << endl;
	fstr << "<table class=\"example\">" << endl;
	fstr << "<caption>" << "Metrics Summary" << "</caption>" << endl;

	fstr << "<thead>" << endl;
	fstr << "<tr>" << endl;

	put_th("Metrics");
	put_th("Value");

	fstr << "</tr>" << endl;
	fstr << "</thead>" << endl;

	fstr << "<tbody>" << endl;

	put_metrics(node);

	fstr << "</tbody>" << endl;
	fstr << "</table>" << endl;
}

void CCCC_Html_Stream::put_metrics(NodeImp* node) {
	//	put_row("Lines of Code", node->get_LOC());
	put_row("Lines of Code", node->getLineOfCode());
	put_row("McCabe's Cyclomatic Complexity", node->get_MVG());
	//	put_row("Lines of Comments", node->get_COM());
	put_row("Lines of Comments", node->getLineOfComm());
	put_row("Lines of Source Code", node->getLineOfSrc());

	float temp_f = (float) node->getLineOfCode() / node->getLineOfComm();

	put_row("Lines of Code per Line of Comment", temp_f);
	put_row("Cyclomatic Complexity per Line of Comment", node->get_M_C());

#ifdef DEBUG
	put_row("Information Flow measure inclusive", node->get_IF4());
	put_row("Information Flow measure visible", node->get_IF4v());
	put_row("Information Flow measure concrete", node->get_IF4c());
#endif

	if (node->get_type() != ntFile) {
		if (node->get_type() == ntProj)
			put_row("Number of Components", node->get_NOC());
		if (node->get_type() == ntProj || node->get_type() == ntCom)
			put_row("Number of Modules", node->get_NOM());
		if (node->get_type() == ntProj || node->get_type() == ntCom
				|| node->get_type() == ntMod)
			put_row("Number of Submodules", node->get_NOSM());
		if (node->get_type() == ntProj || node->get_type() == ntCom
				|| node->get_type() == ntMod || node->get_type() == ntSmod)
			put_row("Number of Files", node->get_NOF());
	}

	put_row("Number of Validation", node->get_NOV());
	put_row("Number of Function Average", node->get_NOFA());
	put_row("Number of Non Default Visibility Header", node->get_NONDVH());
	put_row("Number of Direct Data in Module Interface", node->get_NODDIMI());
	put_row("Number of Abctract Interface", node->get_NOAI());

	if (node->get_type() != ntProj) {
		put_row("Number of Special IFDEF", node->getNumOfSpeIf());
		put_row("Fan in", node->get_FANIN());
		put_row("Fan out", node->get_FANOUT());
	}

	//	if (node->get_type() == ntFile) {
	//		put_row("Weighted Methods per Class", node->get_WMC1());
	//		put_row("Weighted Methods per Class visible", node->get_WMCv());
	//		put_row("Depth of Inheritance Tree", node->get_DIT());
	//		put_row("Number of Children", node->get_NOCH());
	//		put_row("Coupling between Objects", node->get_COB());
	//	}

	if (node->get_type() == ntProj) {
		put_row("Number of Special IFDEF in Shared Code",
				node->getShardNumOfSpeIf());
		put_row("LOC Reusability", node->getSharedLineOfCode());
		put_row("LOC Total", node->getLineOfCode());

		temp_f = (float) node->getSharedLineOfCode() / node->getLineOfCode();
		put_row("Project Reusability", temp_f);
	}
}

void CCCC_Html_Stream::put_row(string name, int value) {
	fstr << "<tr>" << endl;
	fstr << "<td>" << endl;
	fstr << name << endl;
	fstr << "</td>" << endl;
	fstr << "<td>" << endl;

	if (value >= 0)
		fstr << value << endl;
	else
		fstr << "--" << endl;
	fstr << "</td>" << endl;
	fstr << "</tr>" << endl;
}

void CCCC_Html_Stream::put_row(string name, float value) {
	fstr << "<tr>" << endl;
	fstr << "<td>" << endl;
	fstr << name << endl;
	fstr << "</td>" << endl;
	fstr << "<td>" << endl;
	if (value >= 0)
		fstr << value << endl;
	else
		fstr << "--" << endl;
	fstr << "</td>" << endl;
	fstr << "</tr>" << endl;
}

void CCCC_Html_Stream::produce_violation_table(NodeImp* node, int nest) {
	fstr << "<br><br><br>" << endl;
	fstr << "<table class=\"example\">" << endl;
	fstr << "<caption>" << "Voilation Summary" << "</caption>" << endl;

	fstr << "<thead>" << endl;
	fstr << "<tr>" << endl;

	put_th("Validation");
	put_th("Path");

	fstr << "</tr>" << endl;
	fstr << "</thead>" << endl;

	fstr << "<tbody>" << endl;

	put_violation_cell(node, nest);

	fstr << "</tbody>" << endl;
	fstr << "</table>" << endl;
}

void CCCC_Html_Stream::put_violation_cell(NodeImp* node, int nest) {
	std::vector<VoilationImp *>::iterator itr;

	for (itr = node->get_voilation()->begin(); itr
			!= node->get_voilation()->end(); itr++) {
		fstr << "<tr>" << endl;

		if (node->get_type() == ntFile)
			put_td(this->create_index((*itr)->get_line(), nest - 1,
					(*itr)->get_abs_path(), (*itr)->get_name()));
		else
			put_td(this->create_index((*itr)->get_line(), nest,
					(*itr)->get_abs_path(), (*itr)->get_name()));

		char linebuf[16];
		sprintf(linebuf, "%d", (*itr)->get_line());

		string hint = (*itr)->get_abs_path() + " : " + linebuf;

		put_td(hint);
		fstr << "</tr>" << endl;
	}
}

void CCCC_Html_Stream::produce_fan_table(NodeImp* node, int nest) {
	fstr << "<br><br><br>" << endl;
	fstr << "<table class=\"example\">" << endl;
	fstr << "<caption>" << "Fan Summary" << "</caption>" << endl;

	fstr << "<thead>" << endl;
	fstr << "<tr>" << endl;

	put_th("Fan In");
	put_th("Fan Out");

	fstr << "</tr>" << endl;
	fstr << "</thead>" << endl;

	fstr << "<tbody>" << endl;

	put_fan_cell(node, nest);

	fstr << "</tbody>" << endl;
	fstr << "</table>" << endl;
}

void CCCC_Html_Stream::put_fan_cell(NodeImp* node, int nest) {
	std::vector<VoilationImp *>::iterator itrin;
	std::vector<VoilationImp *>::iterator itrout;

	itrin = node->get_fanin()->begin();
	itrout = node->get_fanout()->begin();

	//	cout << node->get_fanin()->size() << endl;
	//	cout << node->get_fanout()->size() << endl;

	//	cout << "### in fan " << endl;
	//TODO
	while (itrin != node->get_fanin()->end() || itrout
			!= node->get_fanout()->end()) {
		fstr << "<tr>" << endl;
		if (itrin != node->get_fanin()->end()) {
			if (node->get_type() == ntFile)
				put_td(this->create_index(1, nest - 1, (*itrin)->get_name(),
						(*itrin)->get_name()));
			else
				put_td(this->create_index(1, nest, (*itrin)->get_name(),
						(*itrin)->get_name()));

			itrin++;
		} else
			put_td(" ");

		if (itrout != node->get_fanout()->end()) {
			if (node->get_type() == ntFile)
				put_td(this->create_index(1, nest - 1, (*itrout)->get_name(),
						(*itrout)->get_name()));
			else
				put_td(this->create_index(1, nest, (*itrout)->get_name(),
						(*itrout)->get_name()));
			itrout++;
		} else
			put_td(" ");
		fstr << "</tr>" << endl;
	}

	//	cout << "fan okay" << endl;
}

void CCCC_Html_Stream::put_td(string s) {
	fstr << "<td>" << endl;
	fstr << s << endl;
	fstr << "</td>" << endl;
}

void CCCC_Html_Stream::produce_interface_table(NodeImp* node) {
	fstr << "<br><br><br>" << endl;
	fstr << "<table class=\"example\">" << endl;
	fstr << "<caption>" << "Interface Summary" << "</caption>" << endl;

	fstr << "<thead>" << endl;
	fstr << "<tr>" << endl;

	put_th("Direct Data in Module Interface");
	put_th("Abctract Interface");

	fstr << "</tr>" << endl;
	fstr << "</thead>" << endl;

	fstr << "<tbody>" << endl;

	put_interface_cell(node);

	fstr << "</tbody>" << endl;
	fstr << "</table>" << endl;
}

void CCCC_Html_Stream::put_interface_cell(NodeImp* node) {
	std::vector<VoilationImp *>::iterator itr_d;
	std::vector<VoilationImp *>::iterator itr_a;

	itr_d = node->get_direct_data()->begin();
	itr_a = node->get_abs_interface()->begin();

	while (itr_d != node->get_direct_data()->end() && itr_a
			!= node->get_abs_interface()->end()) {
		fstr << "<tr>" << endl;
		if (itr_d != node->get_direct_data()->end()) {
			put_td((*itr_d)->get_name());
			itr_d++;
		} else
			put_td("");

		if (itr_a != node->get_abs_interface()->end()) {
			put_td((*itr_a)->get_name());
			itr_a++;
		} else
			put_td("");
		fstr << "</tr>" << endl;
	}
}

void CCCC_Html_Stream::produce_function_table(NodeImp* node, int nest) {
	fstr << "<br><br><br>" << endl;
	fstr << "<table class=\"example\">" << endl;
	fstr << "<caption>" << "Function Summary" << "</caption>" << endl;

	fstr << "<thead>" << endl;
	fstr << "<tr>" << endl;

	put_th("Function Name");
	put_th("MVG");

	fstr << "</tr>" << endl;
	fstr << "</thead>" << endl;

	fstr << "<tbody>" << endl;

	put_function_cell(node, nest);

	fstr << "</tbody>" << endl;
	fstr << "</table>" << endl;
}

void CCCC_Html_Stream::put_function_cell(NodeImp* node, int nest) {

	//TODO
	std::vector<VoilationImp *>::iterator itr;

	cout << "#2063 okay" << endl;

	itr = node->getFuncs()->begin();

	cout << "#2067" << endl;

	while (itr != node->getFuncs()->end()) {
		//		put_td((*itr)->get_name);

		fstr << "<tr>";

		put_td(this->create_index((*itr)->get_line(), nest - 1,
				node->getAbs_path(), (*itr)->get_name()));

		put_td_int((*itr)->getMvg());

		fstr << "</tr>" << endl;

		itr ++;

	}
}

void CCCC_Html_Stream::produce_header_table(NodeImp* node) {
	fstr << "<br><br><br>" << endl;
	fstr << "<table class=\"example\">" << endl;
	fstr << "<caption>" << "Interface Summary" << "</caption>" << endl;

	fstr << "<thead>" << endl;
	fstr << "<tr>" << endl;

	put_th("Non Default Visibility Header");

	fstr << "</tr>" << endl;
	fstr << "</thead>" << endl;

	fstr << "<tbody>" << endl;

	put_header_cell(node);

	fstr << "</tbody>" << endl;
	fstr << "</table>" << endl;
}

void CCCC_Html_Stream::put_header_cell(NodeImp* node) {
	std::vector<VoilationImp *>::iterator itr;

	for (itr = node->get_header()->begin(); itr != node->get_header()->end(); itr++) {
		fstr << "<tr>" << endl;
		put_td((*itr)->get_name());
		fstr << "</tr>" << endl;
	}
}

string create_index(int line, string abs_path, string des, string outdir) {
	string temp = "";
	char linebuf[16];

	if (line > 0)
		sprintf(linebuf, "%d", line);
	else
		sprintf(linebuf, "%d", 1);

	temp += abs_path + ":" + pad_string(10, linebuf, " ");

	string retval = "<a href=\"" + temp + "\">" + des + "</a>";

	return retval;
}

string CCCC_Html_Stream::create_index(int line, int nest, string abs_path,
		string name) {
	string temp = "";

	for (int i = 0; i < nest; i++)
		temp += "../";

	temp += "proj_source.html#";

	char linebuf[16];

	if (line > 0)
		sprintf(linebuf, "%d", line);
	else
		sprintf(linebuf, "%d", 1);

	temp += abs_path + ":" + pad_string(10, linebuf, " ");

	string retval = "<a href=\"" + temp + "\">" + name + "</a>";

	return retval;
}
/**********************************************************************************
 *
 */


#ifdef UNIT_TEST
int main()
{
	CCCC_Project *prj_ptr=test_project_ptr();
	CCCC_Html_Stream os(*prj_ptr,"cccc.htm",".");
	return 0;
}
#endif

